﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Xml;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using TFSLBALib;

/*
 *  Main Form of the application
 *  
 *  Pretty much everything is implemented here...
 *  
 *  Possible actions:
 *   - Update the WIT and WIQL of a Process Template from a Team Project
 *   - Update the WIT and WIQL of a Team Project from a Process Template
 *   - Update the WIT and WIQL of a list of Team Projects from a Process Template
 *   - Duplicate a Process Template
 */

namespace WITSynchronizer
{
    public partial class MainForm : Form
    {
    	#region Variables

		/// <summary>
		/// The Team Foundation Server we're connected to
		/// </summary>
    	TeamFoundationServer	TFS = null;

		/// <summary>
		/// The Work Item Store interface
		/// </summary>
		WorkItemStore			WIS = null;

		/// <summary>
		/// The Process Template interface
		/// </summary>
		IProcessTemplates		PTP = null;

		/// <summary>
		/// The Pool of Process Templates
		/// </summary>
		ProcessTemplatePool		PTPool = null;

    	#endregion

    	#region Object Lifetime

		/// <summary>
		/// Constructor
		/// </summary>
    	public MainForm()
        {
            InitializeComponent();
        }

    	#endregion

    	#region UI Handlers

		/// <summary>
		/// Form Closed event handler
		/// </summary>
		/// <param name="sender">Sender object</param>
		/// <param name="e">Arguments</param>
		/// <remarks>We recycle the Process Template pool</remarks>
    	private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
    	{
			if (PTPool != null)
			{
				PTPool.Dispose();
				PTPool = null;
			}
    	}

    	#region Main Menu

		/// <summary>
		/// "Connect" menu item event handler
		/// </summary>
		/// <param name="sender">Sender object</param>
		/// <param name="e">Arguments</param>
		/// <remarks>If the settings are saved and the server is reachable: automatically connects to it. Otherwise asks the user to enter
		/// the URL of the TFS.</remarks>
    	private void MainMenu_ConnectToTFS(object sender, EventArgs e)
    	{
    		TeamFoundationServer tfs = null;

    		// Try to connect to the TFS saved in the settings
    		if (Properties.Settings.Default.TFSURL != "")
    		{
    			tfs = TFSConnectForm.DirectTFSConnect(Properties.Settings.Default.TFSURL);
    			Properties.Settings.Default.TFSURL = "";
    		}

    		// Can't connect to the saved one, ask the user...
    		if (tfs == null)
    		{
    			TFSConnectForm form = new TFSConnectForm();
    			if (form.ShowDialog() != DialogResult.OK)
    			{
    				return;
    			}

    			tfs = form.TFS;

				// Save the new server in the settings
    			if (tfs != null)
    			{
    				Properties.Settings.Default.TFSURL = tfs.Uri.AbsoluteUri;
    				Properties.Settings.Default.Save();
    			}
    		}

    		// Still nothing ? Quit
    		if (tfs == null)
    		{
    			return;
    		}

    		// Check if we finally succeed
    		if ((TFS == null) || (TFS.Uri.AbsoluteUri != tfs.Uri.AbsoluteUri))
    		{
    			TFS = tfs;
    			WIS = TFS.GetService(typeof(WorkItemStore)) as WorkItemStore;
    			PTP = (IProcessTemplates)TFS.GetService(typeof(IProcessTemplates));

				PTPool = new ProcessTemplatePool(TFS);

				SyncModeComboList.Enabled = true;
				StatusLabel.Text = "Connected to the Team Foundation Server. Choose a Sync Mode...";
    		}

    	}

		/// <summary>
		/// "Synchronize" menu item event handler
		/// Depending on the mode a different action wil be triggered
		/// </summary>
		/// <param name="sender">Sender object</param>
		/// <param name="e">Arguments</param>
    	private void MainMenu_Synchronize(object sender, EventArgs e)
    	{
			switch (SyncModeComboList.SelectedIndex)
			{
					// Update PT
				case 0:
					UpdateProcessTemplate();
					break;

					// Update TP
				case 1:
					UpdateTeamProject();
					break;

					// Mass Update TP
				case 2:
					MassUpdateTeamProject();
					break;
			}
    	}

		/// <summary>
		/// "Duplicate Process Template" menu item event handler
		/// </summary>
		/// <param name="sender">Sender oject</param>
		/// <param name="e">Argument</param>
    	private void DuplicateProcessTemplateMenuItem_Click(object sender, EventArgs e)
    	{
			// Display the Process Template duplication form
			DuplicateProcessTemplateForm form = new DuplicateProcessTemplateForm(TFS);
			form.ShowDialog();
    	}

		/// <summary>
		/// "About" button clicked event handler
		/// Display the about form.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
    	private void AboutButton_Click(object sender, EventArgs e)
    	{
    		AboutForm form = new AboutForm();
    		form.ShowDialog();
    	}

    	#endregion

    	#region Form Content

		/// <summary>
		/// Left Combo List selected changed event handler
		/// Change the UI to display the new content and rebuild the right combo list
		/// </summary>
		/// <param name="sender">Sender object</param>
		/// <param name="e">Arguments</param>
    	private void LeftComboList_Changed(object sender, EventArgs e)
    	{
			// Action depends of the current mode
    		switch (SyncModeComboList.SelectedIndex)
    		{
				// Update PT
				case 0:
					// Get the current process template name
					String ptname = LeftComboList.SelectedItem as string;

					// Setup the right combobox
					SetupComboBoxForTeamProject(RightComboList, ptname);
					RightTreeView.BeginUpdate();
					RightTreeView.Nodes.Clear();
					RightTreeView.EndUpdate();

					// Setup the Tree View
					SetupTreeViewForProcessTemplate(ptname, LeftTreeView);
					break;

				// Update TP
				case 1:
					// Set the content of the left treeview
					String tpname = LeftComboList.SelectedItem as string;
					SetupTreeViewForTeamProject(tpname, LeftTreeView);

					// Setup the right combobox
					SetupComboBoxForProcessTemplate(RightComboList, LeftComboList.SelectedItem as string);
					RightTreeView.BeginUpdate();
					RightTreeView.Nodes.Clear();
					RightTreeView.EndUpdate();
					break;

				// Mass update TPs
				case 2:
					break;
    		}
    	}

		/// <summary>
		/// Right combo list selection changed event handler
		/// Change the content of the Right Tree View
		/// </summary>
		/// <param name="sender">Sender object</param>
		/// <param name="e">Arguments</param>
    	private void RightComboList_Changed(object sender, EventArgs e)
    	{
			// Action depends of the current mode
			switch (SyncModeComboList.SelectedIndex)
			{
				// Update PT
				case 0:
				{
					// Set the content of the left treeview
					String tpname = RightComboList.SelectedItem as string;
					SetupTreeViewForTeamProject(tpname, RightTreeView);
					break;
				}
				
				// Update TP
				case 1:
				{
					// Display the Process Template content in the right Tree
					String ptname = RightComboList.SelectedItem as string;
					SetupTreeViewForProcessTemplate(ptname, RightTreeView);
					break;
				}

				// Mass update TPs
				case 2:
				{
					// Display the Process Template content in the right Tree
					String ptname = RightComboList.SelectedItem as string;
					SetupTreeViewForProcessTemplate(ptname, RightTreeView);
					break;
				}
			}
		}

    	#endregion

		/// <summary>
		/// Sync Mode combo list selection changed event handler
		/// Reinitialize the UI with the new mode
		/// </summary>
		/// <param name="sender">Sender object</param>
		/// <param name="e">Arguments</param>
    	private void SyncModeChanged(object sender, EventArgs e)
    	{
    		switch (SyncModeComboList.SelectedIndex)
    		{
				// Update Process Template from Team Project
    			case 0:
					InitUIForPTUpdate();
					break;

				// Update Team Project from Process Template
				case 1:
					InitUIForTPUpdate();
					break;

				// Mass update of Team Projects from Process Template
				case 2:
					InitUIForMassTPUpdate();
					break;
    		}
    	}

		/// <summary>
		/// Left Tree View after check event handler
		/// Check/uncheck the children
		/// </summary>
		/// <param name="sender">Sender object</param>
		/// <param name="e">Arguments</param>
    	private void LeftTreeView_AfterCheck(object sender, TreeViewEventArgs e)
    	{
			// Look for WIT or WIQL root
			if (e.Node.Tag == null) return;
			if ((e.Node.Tag == "WIT") || (e.Node.Tag == "WIQL"))
			{
				// Apply the state to all children
				foreach (TreeNode node in e.Node.Nodes)
				{
					node.Checked = e.Node.Checked;
				}
			}
		}

		/// <summary>
		/// Right Tree View after check event handler
		/// Check/uncheck the children
		/// </summary>
		/// <param name="sender">Sender object</param>
		/// <param name="e">Arguments</param>
    	private void RightTreeView_AfterCheck(object sender, TreeViewEventArgs e)
    	{
			// Look for WIT or WIQL root
			if (e.Node.Tag == null)			return;
			if ((e.Node.Tag == "WIT") || (e.Node.Tag == "WIQL"))
			{
				// Apply the state to all children
				foreach (TreeNode node in e.Node.Nodes)
				{
					node.Checked = e.Node.Checked;
				}
			}
    	}

    	#endregion

    	#region Helpers

		/// <summary>
		/// Check if the given Process Template and Team Project have the same set of Work Item Types
		/// </summary>
		/// <param name="ptname">The Process Template to check</param>
		/// <param name="tpname">The Team Project to check</param>
		/// <returns>Return true if the structure matches, false otherwise</returns>
    	bool CheckWITStructure(string ptname, string tpname)
    	{
    		// Get the WIT List for the Process Template
			ProcessTemplate pt = PTPool[ptname];
    		String[] ptwitlist = pt.GetWITList();

    		// Get the WIT List for the Team Project
    		String[] tpwitlist = GetTeamProjectWITList(tpname);

    		// Build a dictonnary with all the different WIT
    		Dictionary<String, String> dic = new Dictionary<string, string>();
    		foreach (string str in ptwitlist)
    		{
    			dic.Add(str, str);
    		}

    		foreach (string str in tpwitlist)
    		{
    			try
    			{
    				dic.Add(str, str);
    			}
    			catch (Exception)
    			{
    			}
    		}

    		// Now parse that dictionnary and check each item is in both lists
    		foreach (KeyValuePair<string, string> pair in dic)
    		{
    			if (ptwitlist.Contains(pair.Key) == false)	return false;
    			if (tpwitlist.Contains(pair.Key) == false)	return false;
    		}
			
    		return true;
    	}

		/// <summary>
		/// Get the name of all WIT of a given Team Project
		/// </summary>
		/// <param name="tpname">The name of theTeam Project</param>
		/// <returns>A String array containing the WIT names</returns>
    	string[] GetTeamProjectWITList(string tpname)
    	{
    		List<String> WITList = new List<string>();

    		Project tp = WIS.Projects[tpname];
    		if (tp == null) return WITList.ToArray();

    		foreach (WorkItemType type in tp.WorkItemTypes)
    		{
    			WITList.Add(type.Name);
    		}

    		return WITList.ToArray();
    	}

		/// <summary>
		/// Helper that update the status bar and process application events
		/// </summary>
		/// <param name="text">The new text to set in the status bar</param>
		void UpdateStatusText(string text)
		{
			StatusLabel.Text = text;
			Application.DoEvents();
		}

		/// <summary>
		/// Display the unhandled exception form for the user to submit a bug in codeplex
		/// </summary>
		/// <param name="ex"></param>
		public static void ShowExceptionForm(Exception ex)
		{
			UnhandledExceptionForm form = new UnhandledExceptionForm(ex);
			form.ShowDialog();
		}

		/// <summary>
		/// Uncheck the whole Tree View
		/// </summary>
		/// <param name="treeview">The Tree View to uncheck everything</param>
		void UncheckedTreeView(TreeView treeview)
		{
			foreach (TreeNode node in treeview.Nodes)
			{
				_UncheckTreeView(node);	
			}
		}

		void _UncheckTreeView(TreeNode node)
		{
			node.Checked = false;
			foreach (TreeNode treeNode in node.Nodes)
			{
				_UncheckTreeView(treeNode);
			}
		}

    	#endregion

    	#region UI Setup

    	/// <summary>
		/// Clean the main form UI.
		/// Reset all the controls
		/// </summary>
		void ClearUI()
		{
			LeftComboList.Items.Clear();
			RightComboList.Items.Clear();
			LeftTreeView.Nodes.Clear();
			RightTreeView.Nodes.Clear();
		}
		
		/// <summary>
		/// Initialize the UI for Process Template update from Team Project
		/// </summary>
		void InitUIForPTUpdate()
		{
			// UI feedback
			WaitCursor wc = new WaitCursor();
			StatusLabel.Text = "Initialize for Process Template update";

			// Clear the UI
			ClearUI();
			LeftComboList.Enabled = true;
			LeftTreeView.CheckBoxes = false;

			// Set the labels
			LeftLabel.Text = "Choose the Process Template to update";
			RightLabel.Text = "Choose the Team Project to use for the update, then check the items to synchronize";

			// Setup the Process Template ComboBox
			SetupComboBoxForProcessTemplate(LeftComboList, null);

			StatusLabel.Text += " Done!";
		}

		/// <summary>
		/// Initialize the UI for Team Project update from Process Template
		/// </summary>
		void InitUIForTPUpdate()
		{
			// UI feedback
			WaitCursor wc = new WaitCursor();
			StatusLabel.Text = "Initialize for Team Project update";

			// Clear the UI
			ClearUI();
			LeftComboList.Enabled = true;
			LeftTreeView.CheckBoxes = false;

			// Set the labels
			LeftLabel.Text = "Choose the Team Project to update";
			RightLabel.Text = "Choose the Process Template to use for the update, then check the items to synchronize";

			// Setup the Team Project ComboBox
			SetupComboBoxForTeamProject(LeftComboList, null);

			StatusLabel.Text += " Done!";
		}

		/// <summary>
		/// Initialize the UI for Mass Team Project update from Process Template
		/// </summary>
		void InitUIForMassTPUpdate()
		{
			// UI feedback
			WaitCursor wc = new WaitCursor();
			StatusLabel.Text = "Initialize for Team Project update";

			// Clear the UI
			ClearUI();
			LeftComboList.Enabled = false;

			// Set the labels
			LeftLabel.Text = "Check the projects to update";
			RightLabel.Text = "Choose the Process Template to use for the mass Update, then check the items to synchronize";

			// Fill the left Tree View with the Team Projects
			LeftTreeView.CheckBoxes = true;
			LeftTreeView.BeginUpdate();
			foreach (Project project in WIS.Projects)
			{
				TreeNode tn = LeftTreeView.Nodes.Add(project.Name);
				tn.ImageIndex = tn.SelectedImageIndex = 3;
			}
			LeftTreeView.EndUpdate();

			// Fill the right Combo with the Process Templates
			SetupComboBoxForProcessTemplate(RightComboList, null);


			StatusLabel.Text += " Done!";
		}

		/// <summary>
		/// Setup a Combo List to list all the Process Templates
		/// </summary>
		/// <param name="source">The Combo List to fill</param>
		/// <param name="tpfilter">Name of a Team Project (or null) to use as a filter (only Process Templates having the same WIT list will be displayed</param>
		void SetupComboBoxForProcessTemplate(ComboBox source, string tpfilter)
		{
			// Build the combo box that lists the process templates
			source.Items.Clear();

			TemplateHeader[] hdrs = PTP.TemplateHeaders();
			foreach (TemplateHeader hdr in hdrs)
			{
				// Have to filter ?
				if ((tpfilter!=null) && (FilterSimilarMenuItem.Checked==true))
				{
					if (CheckWITStructure(hdr.Name, tpfilter) == false)
						continue;
				}

				source.Items.Add(hdr.Name);
			}
		}

		/// <summary>
		/// Setup a Combo List to list all the Team Project
		/// </summary>
		/// <param name="source">the Combo List to fill</param>
		/// <param name="ptfilter">Name of a Process Template (or null) to use as a filter (only Team Project having the same WIT list will be displayed)</param>
		void SetupComboBoxForTeamProject(ComboBox source, string ptfilter)
		{
			// Build the combo box that lists the process templates
			source.Items.Clear();

			foreach (Project project in WIS.Projects)
			{
				// Have to filter ?
				if ((ptfilter != null) && (FilterSimilarMenuItem.Checked == true))
				{
					if (CheckWITStructure(ptfilter, project.Name) == false)
						continue;
				}

				source.Items.Add(project.Name);
			}
		}

		/// <summary>
		/// Setup a Tree View to display the content of a given Team Project
		/// </summary>
		/// <param name="tpname">Team Project to display</param>
		/// <param name="source">Tree View to fill</param>
		void SetupTreeViewForTeamProject(string tpname, TreeView source)
		{
			try
			{
				// Rebuild the TreeView
				source.BeginUpdate();
				source.Nodes.Clear();

				TreeNode WITNode = source.Nodes.Add("Work Item Type definitions");		WITNode.Tag  = "WIT";
				TreeNode WIQLNode = source.Nodes.Add("Work Item Query definitions");	WIQLNode.Tag = "WIQL";

				Project project = WIS.Projects[tpname];

				foreach (WorkItemType wit in project.WorkItemTypes)
				{
					TreeNode tn = WITNode.Nodes.Add(wit.Name);
					tn.Tag = wit.Name;
					tn.ImageIndex = tn.SelectedImageIndex = 1;
				}

				foreach (StoredQuery query in project.StoredQueries)
				{
					TreeNode tn = WIQLNode.Nodes.Add(query.Name);
					tn.Tag = query.Name;
					tn.ImageIndex = tn.SelectedImageIndex = 2;
				}

				WITNode.Expand();
				WIQLNode.Expand();
			}
			catch (Exception e1)
			{
				MessageBox.Show(e1.ToString(), "Work Item Synchronizer", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			finally
			{
				source.EndUpdate();
			}
		}

		/// <summary>
		/// Setup a Tree View to display the content of a given Process Template
		/// </summary>
		/// <param name="ptname">Name of the Process Template to display</param>
		/// <param name="source">Tree View to fill</param>
		void SetupTreeViewForProcessTemplate(String ptname, TreeView source)
		{
			try
			{
				ProcessTemplate pt = PTPool[ptname];

				// Rebuild the TreeView
				source.BeginUpdate();
				source.Nodes.Clear();

				TreeNode WITNode = source.Nodes.Add("Work Item Type definitions"); WITNode.Tag = "WIT";
				TreeNode WIQLNode = source.Nodes.Add("Work Item Query definitions"); WIQLNode.Tag = "WIQL";

				String[] witlist = pt.GetWITList();
				foreach (string witname in witlist)
				{
					TreeNode witnode = WITNode.Nodes.Add(witname);
					witnode.Tag = witname;
					witnode.ImageIndex = witnode.SelectedImageIndex = 1;
				}

				String[] wiqllist = pt.GetWIQLList();
				foreach (string wiqlname in wiqllist)
				{
					TreeNode witnode = WIQLNode.Nodes.Add(wiqlname);
					witnode.Tag = wiqlname;
					witnode.ImageIndex = witnode.SelectedImageIndex = 2;
				}

				WITNode.Expand();
				WIQLNode.Expand();
			}
			catch (Exception e1)
			{
				MessageBox.Show(e1.ToString(), "Work Item Synchronizer", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			finally
			{
				source.EndUpdate();
			}
		}
    	#endregion

    	#region Update Implementation

		/// <summary>
		/// Update the selected Process Template with the checked items of the selected Team Project
		/// </summary>
    	void UpdateProcessTemplate()
		{
			// Get the Team Project to get the WITs from
			String srctpname = RightComboList.SelectedItem as string;
			Project srctp = WIS.Projects[srctpname];

			// Get the process template to update
			String ptname = LeftComboList.SelectedItem as String;
			ProcessTemplate pt = PTPool[ptname];

			// Warn user
			if (MessageBox.Show(String.Format("Do you want to update the Process Template {0} with items from the Team Project {1}",
				ptname, srctpname), "WIT Synchronizer", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) != DialogResult.Yes)	return;

			// Get the XML definition of all checked WITs for that Team Project
			XmlDocument[] witlist = GetWITToSync(srctp, RightTreeView);

			// Get the current list of WIT (we'll use that later to determine if we're adding a new WIT)
			String[] ptcurwitlist = pt.GetWITList();

			// Update the Process Template with the new WITs
			UpdateStatusText("Updating Work Item Type definitions...");
    		foreach (XmlDocument document in witlist)
    		{
				if (WarnBeforeNewWITMenuItem.Checked == true)
				{
					XmlElement xel = document.DocumentElement.SelectSingleNode("WORKITEMTYPE") as XmlElement;
					String newwitname = xel.GetAttribute("name");

					if (ptcurwitlist.Contains(newwitname) == false)
					{
						DialogResult dr = MessageBox.Show("The Work Item Type: {0} doesn't exist in the Process Template.\r\nAre you sure you want to add it?", "WIT Synchronizer", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
						if (dr == DialogResult.No)		continue;
					}
				}
    			pt.AddWorkItemType(document, true);
    		}

			// Get the Queries to sync
			UpdateStatusText("Updating WIQL definitions...");
			Dictionary<String, XmlDocument> queries = GetWIQLToSync(srctp, RightTreeView);

			// Update the Process Template with the new WIQLs
    		foreach (KeyValuePair<string, XmlDocument> pair in queries)
    		{
    			pt.AddQuery(pair.Key, pair.Value, true);
    		}

			// Upload the Process Template
			UpdateStatusText("Uploading Process Template...");
			pt.Upload(TFS, true);
			UpdateStatusText("Process Template uploaded!");

			UncheckedTreeView(RightTreeView);
		}

		/// <summary>
		/// Update the selected Team Project with the checked items of the selected Process Template
		/// </summary>
    	void UpdateTeamProject()
		{
			String ptname = RightComboList.SelectedItem as String;
			String tpname = LeftComboList.SelectedItem as String;

			// Warn user
			if (MessageBox.Show(String.Format("Do you want to update the Team Project {0} with items from the Process Template {1}",
				tpname, ptname), "WIT Synchronizer", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) != DialogResult.Yes) return;

			UpdateTeamProject(tpname, ptname);

			UncheckedTreeView(RightTreeView);
		}

		/// <summary>
		/// Update all the checked Team Project with the checked items of the selected Process Template
		/// </summary>
    	void MassUpdateTeamProject()
    	{
    		String ptname = RightComboList.SelectedItem as String;

			// Warn user
			if (MessageBox.Show(String.Format("Do you want to update all the selected Team Projects from the Process Template {0}",
				ptname), "WIT Synchronizer", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) != DialogResult.Yes) return;

			foreach (TreeNode node in LeftTreeView.Nodes)
    		{
    			if (node.Checked == true)
    			{
    				String tpname = node.Text;
    				UpdateTeamProject(tpname, ptname);
    			}
    		}

			UncheckedTreeView(LeftTreeView);
			UncheckedTreeView(RightTreeView);
    	}

		/// <summary>
		/// Update a Team Project from a Process Template
		/// </summary>
		/// <param name="tpname">Name of the Team Project to update</param>
		/// <param name="ptname">Name of the Process Template to get items from</param>
    	void UpdateTeamProject(String tpname, String ptname)
		{
			// Get the Proccess Template to use for the update
			ProcessTemplate pt = PTPool[ptname];

			// Get the Team Project to update
			Project tp = WIS.Projects[tpname];

			// Get the XML definition of all checked WITs for that Team Project
			XmlDocument[] witlist = GetWITToSync(pt, RightTreeView);

			// Update the Team Project with the new WITs
			UpdateStatusText("Updating Team Project's Work Item Type definitions...");
			foreach (XmlDocument doc in witlist)
			{
				XmlElement xel = doc.DocumentElement.SelectSingleNode("WORKITEMTYPE") as XmlElement;
				String newwitname = xel.GetAttribute("name");

				if (WarnBeforeNewWITMenuItem.Checked == true)
				{

					if (tp.WorkItemTypes.Contains(newwitname) == false)
					{
						DialogResult dr = MessageBox.Show("The Work Item Type: {0} doesn't exist in the Team Project.\r\nAre you sure you want to add it?", "WIT Synchronizer", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
						if (dr == DialogResult.No) continue;
					}
				}

				// Import the WIT
				UpdateStatusText(String.Format("Importing WIT '{0}'...", newwitname));
				tp.WorkItemTypes.Import(doc.DocumentElement, ptname);
			}

			// Update the Team Project with the new WIQLs
			UpdateStatusText("Updating Team Project's WIQL definitions...");
			Dictionary<String, XmlDocument> queries = GetWIQLToSync(pt, RightTreeView);

			// Update the Process Template with the new WIQLs
			foreach (KeyValuePair<string, XmlDocument> pair in queries)
			{
				// Existing
				bool existingquery = false;

				// Status update
				UpdateStatusText(String.Format("Importing WIQL '{0}'...", pair.Key));
				// Check if the query already exists
				foreach (StoredQuery query in tp.StoredQueries)
				{
					if (query.Name == pair.Key)
					{
						string queryvalue = pair.Value.DocumentElement.SelectSingleNode("Wiql").InnerText;
						query.QueryText = queryvalue;
						query.Update();
						existingquery = true;
						break;
					}
				}

				//				var q2 = tp.StoredQueries.Cast<StoredQuery>().FirstOrDefault(sq => sq.Name == pair.Key);				

				// Add a new query
				if (existingquery == false)
				{
					string queryvalue = pair.Value.DocumentElement.SelectSingleNode("Wiql").InnerText;
					StoredQuery query = new StoredQuery(QueryScope.Public, pair.Key, queryvalue, "");
					tp.StoredQueries.Add(query);
				}
			}
			UpdateStatusText(string.Format("Team Project '{0}' updated!", tpname));
		}

		/// <summary>
		/// Get the list of the WIT checked by the user
		/// </summary>
		/// <param name="obj">Either a 'Project' object if the Tree View displays a Team Project or a 'ProcessTemplate' object if the Tree View is displaying a Process Template</param>
		/// <param name="treeview">The Tree View to get the data from</param>
		/// <returns>An array of XML documents, one per checked WIT</returns>
    	XmlDocument[] GetWITToSync(object obj, TreeView treeview)
		{
			// Checkings
			if (obj==null || treeview==null)		return null;

			// Get the Tree Node corresponding to the WIT list
			TreeNode witroot = null;
			foreach (TreeNode treeNode in treeview.Nodes)
			{
				if (treeNode.Tag == "WIT")
				{
					witroot = treeNode;
					break;
				}
			}

			// Create the list
			List<XmlDocument> xmllist = new List<XmlDocument>();

			// Loop in the TreeView node
			foreach (TreeNode node in witroot.Nodes)
			{
				// Skip if not checked
				if (node.Checked == false)		continue;

				// Get the WIT Name
				String witname = node.Tag as string;

				// Get XML Document from a Team Project
				if (obj is Project)
				{
					WorkItemType WIT;
					WIT = (obj as Project).WorkItemTypes[witname];
					if (WIT != null)
					{
						XmlDocument witdef = WIT.Export(false);
						xmllist.Add(witdef);
					}
				}

				// Get XML Document from a Process Template
				else if (obj is ProcessTemplate)
				{
					ProcessTemplate tp = obj as ProcessTemplate;
					XmlDocument witdef = tp.GetWITDefinition(witname);
					xmllist.Add(witdef);
				}
			}

			return xmllist.ToArray();
		}

		/// <summary>
		/// Get the list of the WIQL checked by the user
		/// </summary>
		/// <param name="obj">Either a 'Project' object if the Tree View displays a Team Project or a 'ProcessTemplate' object if the Tree View is displaying a Process Template</param>
		/// <param name="treeview">The Tree View to get the data from</param>
		/// <returns>A dictionary with the key being the WIQL Name and the value being the XML Document of its definition</returns>
		Dictionary<String, XmlDocument> GetWIQLToSync(object obj, TreeView treeview)
		{
			// Checkings
			if (obj == null || treeview == null) return null;

			// Get the Tree Node corresponding to the WIT list
			TreeNode witroot = null;
			foreach (TreeNode treeNode in treeview.Nodes)
			{
				if (treeNode.Tag == "WIQL")
				{
					witroot = treeNode;
					break;
				}
			}

			// Create the dictionary
			Dictionary<String, XmlDocument> dic = new Dictionary<string, XmlDocument>();

			// Loop in the TreeView node
			foreach (TreeNode node in witroot.Nodes)
			{
			    // Skip if not checked
			    if (node.Checked == false) continue;

			    // Get the WIQL Name
			    String wiqlname = node.Tag as string;

			    // Get XML Document from a Team Project
			    if (obj is Project)
			    {
			        Project project = obj as Project;
			    	foreach (StoredQuery query in project.StoredQueries)
			    	{
			    		if (query.Name == wiqlname)
			    		{
							XmlDocument xml = new XmlDocument();
							xml.LoadXml("<WorkItemQuery Version=\"1\"><Wiql/></WorkItemQuery>");
							xml.DocumentElement.SelectSingleNode("Wiql").InnerText = query.QueryText;
			    			dic.Add(wiqlname, xml);
			    		}
			    	}
			    }

			    // Get XML Document from a Process Template
			    else if (obj is ProcessTemplate)
			    {
					ProcessTemplate tp = obj as ProcessTemplate;
					XmlDocument wiqldoc = tp.GetWIQLDefinition(wiqlname);

					dic.Add(wiqlname, wiqldoc);
			    }
			}

			return dic;
		}

		#endregion
    }
}
